import pandas as pd
import joblib
import numpy as np
import os


def recursive_predict(model, initial_data, features, forecast_days=14):
    """递归预测未来多天销量 - 修正版"""
    predictions = []
    current_data = initial_data.copy()

    # 创建临时数据结构
    current_features = pd.DataFrame([current_data])

    for day in range(1, forecast_days + 1):
        # 更新天数
        current_day = current_data['days_since_launch'] + day
        current_features['days_since_launch'] = current_day

        # 更新指数衰减特征
        current_features['exp_decay'] = np.exp(-0.03 * current_day)

        # 更新周期性特征
        # current_features['day_of_week'] = current_day % 7

        # 准备预测特征
        X_pred = current_features[features]

        # 预测销量
        pred_sale = model.predict(X_pred)[0]
        pred_sale = max(0, float(pred_sale))  # 确保非负

        # 保存预测结果
        predictions.append({
            'days_since_launch': int(current_day),
            'predicted_sale_qty': pred_sale
        })

        # 更新滞后特征用于下一次预测
        # 注意：这里只更新数据结构，不用于当前预测
        # current_data['lag7'] = current_data['lag1']
        # current_data['lag1'] = pred_sale

        # # 更新移动平均（简化计算）
        # current_data['rolling7_mean'] = (current_data['rolling7_mean'] * 6 + pred_sale) / 7
        # current_data['rolling14_mean'] = (current_data['rolling14_mean'] * 13 + pred_sale) / 14
        #
        # # 更新当前特征数据
        # current_features['lag1'] = current_data['lag1']
        # current_features['lag7'] = current_data['lag7']
        # current_features['rolling7_mean'] = current_data['rolling7_mean']
        # current_features['rolling14_mean'] = current_data['rolling14_mean']

    return predictions


def predict_with_lightgbm(models_file, data_file, forecast_days=14):
    """使用训练好的LightGBM模型递归预测未来销量 - 修正版"""
    # 检查模型文件是否存在
    if not os.path.exists(models_file):
        print(f"❌ 模型文件 {models_file} 不存在")
        return pd.DataFrame()

    # 检查数据文件是否存在
    if not os.path.exists(data_file):
        print(f"❌ 数据文件 {data_file} 不存在")
        return pd.DataFrame()

    # 加载模型
    try:
        models = joblib.load(models_file)
        print(f"✅ 成功加载模型文件，包含 {len(models)} 个款号的模型")
    except Exception as e:
        print(f"❌ 加载模型文件时出错: {e}")
        return pd.DataFrame()

    # 加载历史数据
    try:
        df = pd.read_excel(data_file)
        print(f"✅ 成功加载数据文件，包含 {len(df)} 条记录")
    except Exception as e:
        print(f"❌ 加载数据文件时出错: {e}")
        return pd.DataFrame()

    # 存储预测结果
    all_predictions = []
    processed_spus = 0

    # 对每个款号进行预测
    for spu, model_info in models.items():
        # 获取该款号的最新数据
        spu_data = df[df['spu_code'] == spu]

        if len(spu_data) == 0:
            print(f"⚠️ 未找到款号 {spu} 的数据")
            continue

        try:
            print(f"\n预测款号 {spu}...")

            # 创建最新数据的特征
            latest_data = spu_data.iloc[-1].to_dict()
            latest_df = pd.DataFrame([latest_data])
            latest_df = create_features(latest_df)

            # 获取模型和特征列表
            model, features = model_info

            # 使用递归方法预测未来多天
            predictions = recursive_predict(model, latest_df.iloc[0], features, forecast_days)

            # 添加款号信息
            for pred in predictions:
                pred['spu_code'] = spu
                all_predictions.append(pred)

            processed_spus += 1
            print(f"✅ 款号 {spu} 预测完成 ({len(predictions)}天预测)")

        except Exception as e:
            print(f"❌ 预测款号 {spu} 时出错: {e}")

    # 转换为DataFrame
    result_df = pd.DataFrame(all_predictions)

    if len(result_df) > 0:
        print(f"\n✅ 成功生成 {len(result_df)} 条预测记录")
        print(f"📊 预测款号数量: {processed_spus}")
    else:
        print("\n⚠️ 未生成任何预测记录")

    return result_df


# 特征创建函数（与训练阶段相同）
def create_features(df):
    df = df.copy()
    # df['lag1'] = df.groupby('spu_code')['sale_qty'].shift(1)
    # df['lag7'] = df.groupby('spu_code')['sale_qty'].shift(7)
    # df['rolling7_mean'] = df.groupby('spu_code')['sale_qty'].transform(
    #     lambda x: x.rolling(7, min_periods=1).mean().shift(1))
    # df['rolling14_mean'] = df.groupby('spu_code')['sale_qty'].transform(
    #     lambda x: x.rolling(14, min_periods=1).mean().shift(1))
    df['exp_decay'] = np.exp(-0.03 * df['days_since_launch'])
    # df['day_of_week'] = df['days_since_launch'] % 7
    df.fillna(0, inplace=True)
    return df


if __name__ == "__main__":
    # 执行预测
    future_sales = predict_with_lightgbm(
        models_file='enhanced_lightgbm_models.pkl',
        data_file='sales-LO2502025-30.xlsx',
        forecast_days=14
    )

    if not future_sales.empty:
        # 保存结果
        output_file = "predict.xlsx"
        future_sales.to_excel(output_file, index=False)
        print(f"\n✅ 预测结果已保存为 {output_file}")

        # 打印摘要
        print("\n预测结果摘要:")
        print(future_sales.groupby('spu_code').size().reset_index(name='预测天数'))

        # 检查预测值是否变化
        same_value_check = future_sales.groupby('spu_code')['predicted_sale_qty'].nunique()
        print("\n预测值变化检查:")
        for spu, count in same_value_check.items():
            status = "✅ 有变化" if count > 1 else "⚠️ 全部相同"
            print(f"款号 {spu}: {status} ({count}个不同值)")

        # 显示前2个款号的预测结果
        print("\n预测结果示例:")
        for spu in future_sales['spu_code'].unique()[:2]:
            spu_pred = future_sales[future_sales['spu_code'] == spu]
            print(f"\n款号 {spu} 预测结果:")
            print(spu_pred[['days_since_launch', 'predicted_sale_qty']].head(14))
    else:
        print("\n⚠️ 未保存预测结果")